Redis

official::Redis


一、简单使用

1 简介

Redis(Remote Dictionary Server),基于内存的数据存储系统,非关系型数据库,用作数据库缓存和消息队列等各种场景。

访问方式:

  • CLI:使用Redis-CLI命令行工具使用Redis
  • API:使用Java或Python通过编写代码的方式访问Redis
  • GUI:图形化界面使用Redis,如:RedisInsight

优势:

  • 性能极高
  • 数据类型丰富,单键值对最大支持512M大小的数
  • 简单易用,支持所有主流编程语言
  • 支持数据持久化、主从复制、哨兵模式等高可用特性

2 使用

2.1 linux

安装:

  • sudo apt update
  • sudo apt install redis-server

查看Redis服务是否正在运行:sudo systemctl status redis-server

检查Redis是否成功安装并运行,如果返回 PONG,则表示Redis正常工作:redis-cli ping

启动服务(端口:6379):命令redis-server

管理:

  • 启动Redis服务:sudo systemctl start redis-server
  • 停止Redis服务:sudo systemctl stop redis-server
  • 重新启动Redis服务:sudo systemctl restart redis-server

2.2 windows

Window下Redis的安装和部署详细图文教程

安装:

  1. 安装WSL,用WSL系统安装一个Linux,将Redis安装在Linux中
  2. 安装Docker将Redis安装在Docker中
  3. 官网安装(但版本较老,只有5.0):official::Releases · tporadowski/redis

启动服务(端口:6379):命令redis-server.exe

2.3 管理

管理redis:


二、数据类型

1 Key

键。

# 删除键值(0:失败,1:成功)
DEL <key>

# 判断键存在(0:不存在,1:存在)
EXISTS <key>

# 查找键(pattern匹配模式)
KEYS * # 全匹配
KEYS *me # 以me结尾

# 清空键
FLUSHALL

# 查看键的过期时间(-1:永久,-2:过期)
TTL <key>

# 设置过期时间(单位:秒)
EXPIRE <key> <time>

# 自增1(仅整数)
INCR <key>

2 String

字符串。

redis的存储都是以二进制的形式存储的,所以在存储中文时会直接将值转化成二进制形式,此时使用GET key命令获得的是原始的十六进制。如果要显示中文则可以使用以下命令进入redis:redis-cli --raw。此时中文将被显示。

Redis 字符串(String) | 菜鸟教程 (runoob.com)

# 设置键值
SET <key> <value>

# 获得键值
GET <key> <value>

# 设置一个带有过期时间的键值对
SETEX <key> <time> <value>

# 当键不存在时才设置值,否则不做任何操作(0:失败,1:成功)
SETNX <key> <value>

3 List

列表。

此处的key指的是列表的名称

Redis 列表(List) | 菜鸟教程 (runoob.com)

# 添加数据
LPUSH <key> <value> [<value> ...] # 头加
RPUSH <key> <value> [<value> ...] # 尾加

# 获得数据(0开始,-1表示最后一个元素,范围是:[start,end])
LRANGE <key> <start> <end>

# 删除元素(返回被删除元素,加上count表示被删除的个数)
LPOP <key> [<count>]
RPOP <key> [<count>]

# 列表长度
LLEN <key>

# 保留列表中范围内的元素(0开始,-1表示最后一个元素,范围是:[start,end])
LTRIM <key> <start> <end>

# 先进先出队列
RPOPLPUSH source destination

4 Set

集合

# 添加数据
SADD <key> <value> [<value>]

# 查看元素
SMEMBERS <key>

# 判断元素在集合中
SISMEMBER <key> <value>

# 删除元素(0:失败,1:成功)
SREM <key> <value>

# 集合运算
SINTER <key> <key> # 交
SUNION <key> <key> # 并
SDIFF <key> <key> # 差

5 SortedSet

有序集合

不同的是每个元素都会关联一个 double 类型的分数。redis 正是通过分数来为集合中的成员进行从小到大的排序。

有序集合的成员是唯一的,但分数(score)却可以重复。

Redis 有序集合(sorted set) | 菜鸟教程 (runoob.com)

# 添加元素
ZADD <key> <score> <value> [<score> <value> ...]

# 查看元素
ZRANGE <key> <start> <end>
ZRANGE <key> <start> <end> WITHSCORES # 同时查看分数

# 分数查询
ZSCORE <key> <value>

# 分数排名
ZRANK <key> <value> # 升序
ZREVRANK <key> <value> # 降序

# 删除元素
ZREM <key> <value>

6 Hash

哈希。

key:hash表的名称。

field:键名。

value:键值。

Redis 哈希(Hash) | 菜鸟教程 (runoob.com)

# 添加元素
HSET <key> <field> <value>

# 获得键对应的值
HGET <key> <field>

# 获得所以键值(第一行是第一个键,第二行是第一个值,依次类推)
HGETALL <key> <field>

# 删除键值对
HDEL <key> <field>

# 判断键值存在
HEXISTS <key> <field>

# 获得所有键
HKEYS <key>
# 获得所有值
HVALS <key>

# 元素个数
HLEN <key>

7 Stream

消息队列。

Redis Stream | 菜鸟教程 (runoob.com)

# 向制定消息队列中添加信息(*指任意ID),返回消息的ID
XADD <key> * <field> <value>
XADD <key> 1-0 <field> <value> # 手动指定ID,第一个数字表示时间戳,第二个表示序列号

# 查看消息数量
XLEN <key>

# 查看消息
XRANGE <key> <start> <end>
XRANGE <key> - + # 查看所有消息

# 删除消息
XDEL <key> <ID>

# 裁剪消息
XTRIM <key> MAXLEN <num>
XTRIM myStream MAXLEN 100 # 保留前100条(包括100)
XTRIM myStream MAXLEN 200 ~ # 保留前200条(不包括200)


# 读取信息(COUNT:一次性读几条,BLOCK:没有消息阻塞num毫秒,最后的数字表示从索引几开始)
XREAD COUNT <num> BLOCK <num> STREAMS <key> <index>
XREAD COUNT 2 BLOCK 1000 STREAMS myStream 0
XREAD COUNT 2 BLOCK 10000 STREAMS myStream $ # 获得新消息

# 创建消费者组
XGROUP CREATE <key> <group> <ID>
XGROUP CREATE myStream group1 0

# 查看消费者组信息
XINFO GROUPS <key>


# 创建消费者
XGROUP CREATECONSUMER <key> <group> <consumer>
XGROUP CREATECONSUMER myStream group1 consumer1

# 读取组中消息
XREADGROUP GROUP <group> <consumer> COUNT <num> BLOCK <num> STREAMS <key> <index>
XREADGROUP GROUP group1 consumer1 COUNT 2 BLOCK 3000 STREAMS myStream > # 读取最新消息

8 Geospatial

地理空间。

Redis GEO | 菜鸟教程 (runoob.com)

# 添加城市信息(返回成功添加的城市的数量)
GEOADD CITY <longitude> <latitude> <value>

# 获取城市经纬度
GEOPOS CITY <value>

# 计算两城市的直线距离(单位:公里)
GEODIST CITY <value1> <value2>
GEODIST CITY Beijing Shanghai KM # 单位用千米

# 查找城市周围的城市(Param:BYRADIUS:圆形、BYBOX:矩形)
GEOSERACH CITY FROMMEMBER <value> <Param> <num>
GEOSERACH CITY FROMMEMBER Shanghai BYRADIUS 1000 KM # 查找上海周围1000KM的城市

9 Log

HyperLog。

用于做基数统计的算法。

基数是指数据集中不重复元素的个数。因为HyperLog内部实现是随机算法,所以在计算大数据时可能会存在一定的误差。因此适合用来做一些对精确度要求不高的大数据统计。比如统计某个词的搜索次数。

Redis HyperLogLog | 菜鸟教程 (runoob.com)

# 添加基数
PFADD <key> <value>

# 查看基数
PFCOUNT <key>

# 合并课程(0 = 1+2)
PFMERGE <key0> <key1> <key2>

10 Bitmap

位图。

对二进制位进行操作。通过偏移量来控制具体的位置。

BITMAP实质上是String的扩展,所以用String设置值也可以。

# 设置对应位图对应偏移上的值(0或1)
SETBIT <key> <offset> <value>
SETBIT coin 0 1
SETBIT coin 1 0

# 获得对应位图对应偏移上的值
GETBIT <key> <offset>

# 字符串方式设置
SET <key> <value>

# 统计有多少个1
BITCOUNT <key>

# 返回第一个出现的value的索引(可以指定范围)
BITPOS <key> <value> [start [end]]
BITPOS coin 0
BITPOS coin 1
# 设置coin值为11110000(可以用十六进制方式设置)
SET coin "\xF0"

# 获得值(发现前四位是1,后四位是0,大端存储)
GETBIT coin 0
GETBIT coin 1
GETBIT coin 5
GETBIT coin 6

11 Bitfield

位域。

位域可以将很多小的整数存储到一个较大的位图中,这样可以更加高效地使用内存。

# 设置位域(code:编码,#index:位置)
BITFIELD <key> SET <code> #<index> <value>

# 获得位域
BITFIELD <key> GET <code> #<index> <value>

# 增加位域的值
BITFIELD <key> incrby <code> #<index> <value>
# 假设你是一位游戏玩家,你有level、money、exp等属性,可以进行如下设置: 
# 玩家1等级设置为1(u8:无符号8位整形)
BITFIELD player:1 SET u8 #0 1
# 玩家1金钱设置为100(u32:无符号32位整形)
BITFIELD plyaer:1 SET u32 #1 100

# 玩家1击杀怪物后获得了100金币
BITFIELD player:1 incrby u32 #1 100

三、应用

1 订阅

一种消息通信模式。发送者发送消息,订阅者接收消息。

在订阅者订阅消息后将一直监听发送者,当有新消息通过PUBLISH命令发送给对应频道时,这个消息就会被发送给对应的客户端。

普通发送的消息无法持久化,无法记录历史消息。但是发布Stream则可以解决这些问题。

Redis 发布订阅 | 菜鸟教程 (runoob.com)

# 订阅频道
SUBSCRIBE <channel>

# 取消订阅
PUNSUBSCRIBE <channel>

# 发布消息
PUBLISH <channel> <information>

2 事务

Redis 事务 | 菜鸟教程 (runoob.com)

在关系型数据库中,事务一般是一个原子操作,要么全部执行成功,要么全部执行失败。

在Redis,事务不能保证每一个命令都会执行成功,但是Redis可以保证以下几点:

  • 批量操作在发送 EXEC 命令前被放入队列缓存。
  • 收到 EXEC 命令后进入事务执行,事务中任意命令执行失败,其余的命令依然被执行。
  • 在事务执行过程,其他客户端提交的命令请求不会插入到事务执行命令序列中。
# 开启事务(开启后命令提示符后面会多一个(TX))
MULTI

# 之后可以在事务状态下输入命令,返回QUEUED表示命令被放到了队列中
SET k1 v1
SET k2 v2

# 执行刚刚设置的事务
EXEC
# 某一个命令失败后面的命令依然会被执行
SET k1 1
SET k2 v2
SET k3 3
MULTI
INCR k1
INCR k2
INCR k3
EXEC
GET k1
GET k2
GET k3

3 持久化

RDB(Redis Database):指在指定时间间隔内,将内存中的数据快照写入磁盘。适合做备份。

因为在save的过程中,redis主线程会阻塞,不可以做其他任何操作。而使用bgsave时,主线程需要先fork一个库,然后开一个子线程做save操作。但是在fork的时候主线程一样会阻塞。为了解决上述问题,redis提出了下面一个持久化存储的办法。

AOF(Append Only File):追加文件。原理是在执行写命令时,不仅会将命令写入内存中,还会将命令写入一个追加的文件中。该文件会以日志的形式记录每一个写操作。因此,当Redis重启时,它就可以通过重新执行AOF文件中的命令来在内存中重建整个数据库的内容。AOF需要手动开启。

# 修改配置
vi redis.conf

# 修改快照配置
vi redis.conf
/save

# 保存快照(此时主线程不可以做其他事)
save

# 查看快照文件
exit
ls -ltr
xxd dump.rdb

# 每天凌晨4点自动备份一次并转移快照文件到别的路径
crontab -e # 打开crontab
0 4 * * * redis-cli save && cp /var/lib/redis/dump.rdb /your/backup/path/ # 末尾添加命令保存即可

# 单独开辟一个子线程保存快照(主线程可以做其他事)
bgsave

# 开启AOF
vi redis.conf
appendonly yes # 将no改成yes

4 主从复制

将主节点的数据复制给从节点。一个主节点可以有多个从节点,但是一个从节点只能有一个主节点。

数据的复制是单向的,只能由主节点到从节点。主节点复制写操作,从节点负责读操作。主节点会将自己的数据变化通过异步的方式发给从节点。从节点收到数据后更新自己的数据。

下面是修改从节点的方式。(主节点不需要修改,因为默认就是主节点)

# 方法1:指定主节点(不常用)
SLAVEOF <host> <port>

# 方法2:修改redis.conf
# 找到redis配置文件,复制一份
cp redis.conf redis-6380.conf
# 打开配置文件
vi redis-6380.conf

port 6380 # 修改端口号
pidfile /var/run/redis_6380.pid # 修改进程ID
dbfilename dump-6380.rdb # 修改备份文件名
replicaof 127.0.0.1 6379 # 复制一行,删除注释,指定主节点

# 使用指定配置文件启动新启动一个redis
redis-server redis-6380.conf

# 指定端口启动一个客户端
redis-cli -p 6380

# 启动后可以查看身份
info replication

role # 查看身份:slave、master
connected_slaves # 主节点查看链接的从节点个数

5 哨兵模式

当主节点宕机后,需要手动配置将从节点提升为主节点。

利用redis的哨兵模式,则可以自动地将从节点提升为主节点。

哨兵会以一个独立的进程运行在Redis集群中,用来监控Redis中的各个节点是否运行正常。主要功能如下:

  1. 监控:通过不断发送命令来检查Redis节点是否正常。
  2. 通知:当发现某个节点出现问题,哨兵就会通过发布订阅模式来通知其他节点。
  3. 自动故障转移:当主节点不能工作以后,哨兵将会将一个从节点升级为新的主节点,然后将其他从节点指向新的主节点。

实际生产环境中,哨兵节点也存在宕机的可能。因此一般会设置三个哨兵节点,这三个哨兵节点会通过选举的方式来选出一个领导者,然后由领导者来监控其他节点。领导挂了则其他哨兵节点会重新选举出一个领导者。

# 新建哨兵文件
vi sentinel.conf

# 添加下列数据
# 指定主节点IP和PORT,1表示只要1个哨兵节点同意就可以故障转移了
sentinel monitor master 127.0.0.1 6379 1

# 启动哨兵节点
redis-sentinel sentinel.conf